package com.geeke.config.crypto;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

import javax.servlet.ServletInputStream;

import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.connector.Request;
import org.apache.commons.io.IOUtils;
import org.apache.tomcat.util.http.Parameters;
import org.apache.tomcat.util.http.Parameters.FailReason;

import com.geeke.sys.entity.Security;
import com.geeke.sys.service.SecurityService;
import com.geeke.utils.AesUtils;
import com.geeke.utils.SpringUtils;



public class CryptoRequest extends Request {

    private static SecurityService securityService = null;
    private static SecurityService getSecurityService() {
        if(securityService ==null) {
            securityService = SpringUtils.getBean(SecurityService.class);
        }
        return securityService;
    }
    

    public CryptoRequest(Connector connector) {
        super(connector);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        SecurityService securityService = getSecurityService();
        Security security = securityService.get("1");
        ServletInputStream inputStream = super.getInputStream();
        // 数据解密key
        String key = getEncryptKey();
        if(key != null) {
            try {
                // 是否需要判断body长度为0的情况
                String body = IOUtils.toString(inputStream);
                String text = AesUtils.dencrypt(body, key, security.getCryptoIv());

                String contentType = getContentType();
                // 客户端通过FormData上传时，由于加密前的数据未转成二进制直接流，需要在后端处理
                if(contentType != null && contentType.contains("multipart/form-data;")) {
                    byte[] array = new byte[text.length()];
                    for(int i = 0; i < text.length(); i++) {
                        array[i] = (byte) text.charAt(i);
                    }
                    inputBuffer.setByteBuffer(ByteBuffer.wrap(array));
                } else {
                    inputBuffer.setByteBuffer(ByteBuffer.wrap(text.getBytes(StandardCharsets.UTF_8)));
                }


            } catch (Exception e) {
                e.printStackTrace();
                throw new IOException("解密失败");
            }
        }
        return inputStream;
    }


    @Override
    protected void parseParameters() {
        // 数据解密Key
        String key = getEncryptKey();
        if ( key != null
            && "application/x-www-form-urlencoded".equals(getContentType())
            && !"chunked".equalsIgnoreCase(coyoteRequest.getHeader("transfer-encoding"))) {
                parsePostParameters(key);
                return;
        }

        super.parseParameters();
    }

    private String getEncryptKey() {
        return coyoteRequest.getMimeHeaders().getHeader("encrypt-key");
    }

    private void parsePostParameters(String key) {
        parametersParsed = true;
        Parameters parameters = coyoteRequest.getParameters();
        parameters.setLimit(getConnector().getMaxParameterCount());

        boolean success = false;
        try {
            int len = getContentLength();
            if (len > 0) {
                int maxPostSize = connector.getMaxPostSize();
                if ((maxPostSize >= 0) && (len > maxPostSize)) {
                    Context context = getContext();
                    if (context != null && context.getLogger().isDebugEnabled()) {
                        context.getLogger().debug(
                                sm.getString("coyoteRequest.postTooLarge"));
                    }
                    checkSwallowInput();
                    parameters.setParseFailedReason(FailReason.POST_TOO_LARGE);
                    return;
                }
                byte[] formData = null;
                if (len < CACHED_POST_LEN) {
                    if (postData == null) {
                        postData = new byte[CACHED_POST_LEN];
                    }
                    formData = postData;
                } else {
                    formData = new byte[len];
                }
                try {
                    if (readPostBody(formData, len) != len) {
                        parameters.setParseFailedReason(FailReason.REQUEST_BODY_INCOMPLETE);
                        return;
                    }

                    // 解密
                    SecurityService securityService = getSecurityService();
                    Security security = securityService.get("1");
                    String encodeString = new String(formData,0, len);
                    String text = AesUtils.dencrypt(encodeString, key, security.getCryptoIv());
                    formData = text.getBytes(StandardCharsets.UTF_8);
                    len = text.length();
                    
                } catch (Exception e) {
                    // Client disconnect
                    Context context = getContext();
                    if (context != null && context.getLogger().isDebugEnabled()) {
                        context.getLogger().debug(
                                sm.getString("coyoteRequest.parseParameters"), e);
                    }
                    parameters.setParseFailedReason(FailReason.CLIENT_DISCONNECT);
                    return;
                }
                parameters.processParameters(formData, 0, len);
            } 
            success = true;
        } finally {
            if (!success) {
                parameters.setParseFailedReason(FailReason.UNKNOWN);
            }
        }
    }
}
